package controllers

import (
	"context"
	"miners-monitor/models/client"
	"miners-monitor/models/common"
	"miners-monitor/models/expend"
	"miners-monitor/models/income"
	"miners-monitor/models/miner"
	"miners-monitor/models/msg"
	"miners-monitor/models/rewardBurn"
	"miners-monitor/models/total"
	"sync"
	"time"

	"github.com/filecoin-project/go-address"
	"github.com/filecoin-project/go-state-types/abi"
	"github.com/filecoin-project/lotus/build"
	"github.com/filecoin-project/lotus/chain/types"
	. "github.com/milkbobo/fishgoweb/language"
	. "github.com/milkbobo/fishgoweb/web"
	"github.com/shopspring/decimal"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo/options"
)

var YesterdayData sync.Map
var IsSyncExpend bool
var IsSyncIncome bool
var SyncTotalMinersByHeight map[string]int64
var SynYesterdayDataByHeight map[string]int64

type DefineController struct {
	BaseController
	CommonFunc   common.CommonFunc
	TotalAo      total.TotalAoModel
	RewardBurnAo rewardBurn.RewardBurnAoModel
	MessageAo    msg.MessageAoModel
	MinerAo      miner.MinerAoModel
	ExpendAo     expend.ExpendAoModel
	ClientAo     client.ClientAoModel
	IncomeAo     income.IncomeAoModel
}

type MinerGeneralize struct {
	total.TotalMiner
	TodayEveryTibEarnings          float64 // 今天每T收益
	YesterdayEveryTibEarnings      float64 // 昨天每T收益
	YesterdayPowerGrowth           float64 // 昨天算力增长
	TodayPowerGrowth               float64 // 今天算力增长
	ExpectIncreaseComputingPower   float64 // 今天预估密封算力
	TodayRewardFil                 float64
	TodayRewardCount               int
	TodayLucky                     float64
	TodayWinPerDay                 float64 // 今天理论出块数
	YesterdayRewardFil             float64
	YesterdayRewardCount           int
	YesterdayLucky                 float64
	YesterdayWinPerDay             float64 // 昨天理论出块数
	TodayBurnFil                   float64 // 今天罚币
	TodayBurnCount                 int
	YesterdayBurnFil               float64 // 昨天罚币
	YesterdayBurnCount             int
	TodayReductionsBalances        float64 // 今天余额减少量
	YesterdayReductionsBalances    float64 // 昨天余额减少量
	TodayCostPerTib                float64 // 今天每T成本
	TodayCostPerTibByGas           float64 // 今天每T成本的Gas
	TodayCostPerTibByPledge        float64 // 今天每T成本的抵押
	YesterdayCostPerTib            float64 // 昨天每T成本
	YesterdayCostPerTibByGas       float64 // 昨天每T成本的Gas
	YesterdayCostPerTibByPledge    float64 // 昨天每T成本的抵押
	YesterdayCommittedPowerFloat   float64 // 昨天有效算力
	TodayGas                       float64
	YesterdayGas                   float64
	TodayPledge                    float64 // 昨天抵押
	YesterdayPledge                float64 // 今天抵押
	YesterdayBurnList              []rewardBurn.RewardBurnBlock
	TotalRoundWinner               int64   // 累积出块权
	TodayRoundWinner               int64   // 今天出块权
	YesterdayRoundWinner           int64   // 昨天出块权
	TodayReleaseFil                float64 // 释放FIL
	TodayImmediateRelease          float64 // 立即释放
	TodayVesting                   float64 // 线性释放
	YesterdayReleaseFil            float64 // 释放FIL
	YesterdayImmediateRelease      float64 // 立即释放
	YesterdayVesting               float64 // 线性释放
	DoneYesterdaySyncTotal         bool    // 昨天之后的概况数据是否同步好
	DoneYesterdaySyncMsg           bool    // 昨天之后的msg数据是否同步好
	DoneYesterdaySyncRewardPenalty bool    // 昨天之后的奖励罚币数据是否同步好
	IsSyncAllRewardCount           bool    // 是否同步好累积出块数
	DoneSyncVestingFunds           bool    // 昨天之后的奖励罚币数据是否同步好
	DoneRoundWinner                bool    // 昨天之后的出块权数据是否同步好
}

func (this *DefineController) GetMinerTotalByMinerId(minerId string) MinerGeneralize {

	result := MinerGeneralize{}

	nowTime := time.Now().In(common.LocationTime)
	yesterday := nowTime.AddDate(0, 0, -1)
	yesterdayZeroHour := time.Date(yesterday.Year(), yesterday.Month(), yesterday.Day(), 0, 0, 0, 0, common.LocationTime)
	todayZeroHour := time.Date(nowTime.Year(), nowTime.Month(), nowTime.Day(), 0, 0, 0, 0, common.LocationTime)
	YesterdayZeroHeight, err := this.CommonFunc.TimeToEpoch(yesterdayZeroHour.Format("2006-01-02 15:04:05"))
	if err != nil {
		panic(err)
	}

	syncTotalMinersByHeight, ok := SyncTotalMinersByHeight[minerId]
	result.DoneYesterdaySyncTotal = syncTotalMinersByHeight < YesterdayZeroHeight || !ok
	syncMsgByHeight, ok := rewardBurn.SyncMsgMinerMap[minerId]
	result.DoneYesterdaySyncMsg = syncMsgByHeight < YesterdayZeroHeight || !ok
	syncRewardPenaltyMsgByHeight, ok := rewardBurn.SyncRewardMinerMap[minerId]
	result.DoneYesterdaySyncRewardPenalty = syncRewardPenaltyMsgByHeight < YesterdayZeroHeight || !ok
	result.DoneSyncVestingFunds = total.SyncVestingFundsByHeight < YesterdayZeroHeight
	_, result.IsSyncAllRewardCount = rewardBurn.SyncBlockMinerMap[minerId]
	result.IsSyncAllRewardCount = !result.IsSyncAllRewardCount
	result.DoneRoundWinner = total.SyncRoundWinnerMap[minerId] < YesterdayZeroHeight

	minerAddr := this.MinerAo.GetMinerAddress()[minerId]

	YesterdayDataKey := yesterdayZeroHour.String() + "-" + minerId
	yesterdayMinerGeneralize, yesterdayCacheDataOk := YesterdayData.Load(YesterdayDataKey)

	yesterdayCacheData := MinerGeneralize{}
	if yesterdayCacheDataOk {
		yesterdayCacheData, yesterdayCacheDataOk = yesterdayMinerGeneralize.(MinerGeneralize)
	}

	opts := options.FindOne().SetSort(bson.D{{"Height", -1}})
	searchTotal := total.TotalMiner{MinerAddress: minerId}

	result.TotalMiner = this.TotalAo.FindOneStruct(searchTotal, opts)

	result.TotalMiner.TimeString = time.Unix(result.TotalMiner.Time, 0).In(common.LocationTime).Format("2006-01-02 15:04:05")
	QualityAdjPowerDecimal, err := decimal.NewFromString(result.QualityAdjPower)
	if err != nil {
		this.Log.Error("minerId:%+v,err:%+v", minerId, err.Error())
	}
	QualityAdjPowerDecimalByTB := this.CommonFunc.SizeTibConvertByDecimal(QualityAdjPowerDecimal)
	result.QualityAdjPowerFloat, _ = QualityAdjPowerDecimalByTB.Float64()

	CommittedPowerDecimal, err := decimal.NewFromString(result.CommittedPower)
	if err != nil {
		this.Log.Error("minerId:%+v,err:%+v", minerId, err.Error())
	}
	CommittedPowerDecimalByTB := this.CommonFunc.SizeTibConvertByDecimal(CommittedPowerDecimal)
	result.CommittedPowerFloat, _ = CommittedPowerDecimalByTB.Float64()

	result.TotalBalanceFloat, err = this.CommonFunc.FilConvert(result.TotalBalance)
	if err != nil {
		this.Log.Error("minerId:%+v,err:%+v", minerId, err.Error())
	}

	result.WorkerBalanceFloat, err = this.CommonFunc.FilConvert(result.WorkerBalance)
	if err != nil {
		this.Log.Error("minerId:%+v,err:%+v", minerId, err.Error())
	}

	result.OwnerBalanceFloat, err = this.CommonFunc.FilConvert(result.OwnerBalance)
	if err != nil {
		this.Log.Error("minerId:%+v,err:%+v", minerId, err.Error())
	}

	allReward := this.RewardBurnAo.FindByStruct(rewardBurn.RewardBurnBlock{To: minerId, From: "f02"}, options.Find())
	decimalRawardTotal := decimal.Decimal{}
	for _, v := range allReward {
		result.RewardCount++
		if v.Value != "" {
			rewardNumsDecimal, err := decimal.NewFromString(v.Value)
			if err != nil {
				this.Log.Error("minerId:%+v,err:%+v", minerId, err.Error())
			}
			decimalRawardTotal = decimalRawardTotal.Add(rewardNumsDecimal)
		}
	}

	result.RewardNums = decimalRawardTotal.String()
	result.RewardNumsFloat, _ = this.CommonFunc.FilConvertByDecimal(decimalRawardTotal).Float64()

	opts = options.FindOne().SetSort(bson.D{{"Height", -1}})
	todayRewardSeard := bson.D{{"To", minerId}, {"From", "f02"}, {"Time", bson.D{{"$gte", todayZeroHour.Unix()}}}}
	todayReward := this.RewardBurnAo.Find(todayRewardSeard, options.Find())
	todayRewardDecimal := decimal.NewFromInt(0)
	if len(todayReward) > 0 {
		for _, singleReward := range todayReward {
			singleRewardDecimal, err := decimal.NewFromString(singleReward.Value)
			if err != nil {
				this.Log.Error("minerId:%+v,err:%+v", minerId, err.Error())
			}
			todayRewardDecimal = todayRewardDecimal.Add(singleRewardDecimal)
			result.TodayRewardCount++
		}

		result.TodayRewardFil, _ = this.CommonFunc.FilConvertByDecimal(todayRewardDecimal).Float64()
	}

	todayZeroHourBlock := this.TotalAo.FindOne(bson.D{{"MinerAddress", minerId}, {"Time", bson.D{{"$eq", todayZeroHour.Unix()}}}}, opts)
	if todayZeroHourBlock.Height == 0 {
		todayZeroHourBlock = this.TotalAo.FindOne(bson.D{{"MinerAddress", minerId}, {"Time", bson.D{{"$eq", todayZeroHour.Unix() - 30}}}}, opts)
	}
	tipSet, err := common.LotusApi.ChainGetTipSetByHeight(context.TODO(), abi.ChainEpoch(todayZeroHourBlock.Height), common.NowTipSet.Key())
	if err != nil {
		panic(err)
	}

	todayZeroHourPow, err := common.LotusApi.StateMinerPower(context.TODO(), minerAddr, tipSet.Key())
	if err != nil {
		panic(err)
	}

	nowPow, err := common.LotusApi.StateMinerPower(context.TODO(), minerAddr, common.NowTipSet.Key())
	if err != nil {
		panic(err)
	}

	if !nowPow.MinerPower.QualityAdjPower.IsZero() && !nowPow.TotalPower.QualityAdjPower.IsZero() {
		qpercI := types.BigDiv(types.BigMul(nowPow.MinerPower.QualityAdjPower, types.NewInt(1000000)), nowPow.TotalPower.QualityAdjPower)
		expWinChance := float64(types.BigMul(qpercI, types.NewInt(build.BlocksPerEpoch)).Int64()) / 1000000
		if expWinChance > 0 {
			if expWinChance > 1 {
				expWinChance = 1
			}
			winRate := time.Duration(float64(time.Second*time.Duration(build.BlockDelaySecs)) / expWinChance)
			result.TodayWinPerDay = float64(time.Hour*24) / float64(winRate)
			result.TodayLucky = float64(result.TodayRewardCount) / result.TodayWinPerDay * 100
		}
	}

	todayZeroCommittedPowerDecimal, err := decimal.NewFromString(todayZeroHourBlock.CommittedPower)
	if err != nil {
		this.Log.Error("minerId:%+v,err:%+v", minerId, err.Error())
	}

	todayZeroQualityAdjPowerDecimal, err := decimal.NewFromString(todayZeroHourBlock.QualityAdjPower)
	if err != nil {
		this.Log.Error("minerId:%+v,err:%+v", minerId, err.Error())
	}

	todayPledgeDecimal := decimal.NewFromInt(0)
	todayGasDecimal := decimal.NewFromInt(0)
	todayBlocksOpt := options.Find().SetSort(bson.D{{"Height", 1}})
	todayMsg := this.MessageAo.Find(bson.D{{"To", minerId}, {"Time", bson.D{{"$gte", todayZeroHour.Unix()}}}}, todayBlocksOpt)
	for _, singleMsg := range todayMsg {
		if singleMsg.Method == 6 ||
			singleMsg.Method == 7 {
			BaseFeeBurnDecimal, err := decimal.NewFromString(singleMsg.BaseFeeBurn)
			if err != nil {
				this.Log.Error("minerId:%+v,err:%+v", minerId, err.Error())
			}

			OverEstimationBurnDecimal, err := decimal.NewFromString(singleMsg.OverEstimationBurn)
			if err != nil {
				this.Log.Error("minerId:%+v,err:%+v", minerId, err.Error())
			}

			MinerTipDecimal, err := decimal.NewFromString(singleMsg.MinerTip)
			if err != nil {
				this.Log.Error("minerId:%+v,err:%+v", minerId, err.Error())
			}

			todayGasDecimal = todayGasDecimal.Add(BaseFeeBurnDecimal).Add(OverEstimationBurnDecimal).Add(MinerTipDecimal)

			ValueDecimal, err := decimal.NewFromString(singleMsg.Value)
			if err != nil {
				this.Log.Error("minerId:%+v,err:%+v", minerId, err.Error())
			}
			todayPledgeDecimal = todayPledgeDecimal.Add(ValueDecimal)
		}
	}
	result.TodayGas, _ = this.CommonFunc.FilConvertByDecimal(todayGasDecimal).Float64()
	result.TodayPledge, _ = this.CommonFunc.FilConvertByDecimal(todayPledgeDecimal).Float64()

	TodayReductionsBalancesDecimal := todayPledgeDecimal.Add(todayGasDecimal)
	result.TodayReductionsBalances, _ = this.CommonFunc.FilConvertByDecimal(TodayReductionsBalancesDecimal).Float64()

	nowBlock := this.TotalAo.FindOne(bson.D{{"MinerAddress", minerId}}, opts)
	nowBlockCommittedPowerDecimal, err := decimal.NewFromString(nowBlock.CommittedPower)
	if err != nil {
		this.Log.Error("minerId:%+v,err:%+v", minerId, err.Error())
	}

	todayPowerGrowthDecimal := nowBlockCommittedPowerDecimal.Sub(todayZeroCommittedPowerDecimal)
	result.TodayPowerGrowth, _ = this.CommonFunc.SizeTibConvertByDecimal(todayPowerGrowthDecimal).Float64()
	todayZeroQualityAdjPowerFloat, _ := this.CommonFunc.SizeTibConvertByDecimal(todayZeroQualityAdjPowerDecimal).Float64()

	todayHeight := nowBlock.Height - todayZeroHourBlock.Height
	if todayHeight > 0 {
		expectIncreaseComputingPowerDecimal := todayPowerGrowthDecimal.Div(decimal.NewFromInt(todayHeight)).Mul(decimal.NewFromInt(2880))
		result.ExpectIncreaseComputingPower, _ = this.CommonFunc.SizeTibConvertByDecimal(expectIncreaseComputingPowerDecimal).Float64()
	}

	todayBurnList := this.RewardBurnAo.Find(bson.D{{"From", minerId}, {"To", "f099"}, {"Time", bson.D{{"$gte", todayZeroHour.Unix()}}}}, options.Find())
	if len(todayBurnList) > 0 {
		todayBurnDecimal := decimal.NewFromInt(0)
		for _, singleBurn := range todayBurnList {
			singleBurnDecimal, err := decimal.NewFromString(singleBurn.Value)
			if err != nil {
				this.Log.Error("minerId:%+v,err:%+v", minerId, err.Error())
			}
			todayBurnDecimal = todayBurnDecimal.Add(singleBurnDecimal)
			result.TodayBurnCount++
		}
		result.TodayBurnFil, _ = this.CommonFunc.FilConvertByDecimal(todayBurnDecimal).Float64()
	}

	result.TotalRoundWinner = this.TotalAo.CountDocuments(bson.D{{"MinerAddress", minerId}, {"RoundWinner", 1}}, options.Count())
	result.TodayRoundWinner = this.TotalAo.CountDocuments(bson.D{{"MinerAddress", minerId}, {"RoundWinner", 1}, {"Time", bson.D{{"$gte", todayZeroHour.Unix()}}}}, options.Count())
	if result.TodayRoundWinner == 0 {
		if result.TotalMiner.RoundWinner != total.TotalRoundWinnerEnum.YES &&
			result.TotalMiner.RoundWinner != total.TotalRoundWinnerEnum.NO {
			result.DoneRoundWinner = false
		}
	}

	todayZeroHourVestingFundsDecimal, err := decimal.NewFromString(todayZeroHourBlock.VestingFunds)
	if err != nil {
		this.Log.Error("minerId:%+v,err:%+v", minerId, err.Error())
	}
	nowVestingFundsDecimal, err := decimal.NewFromString(nowBlock.VestingFunds)
	if err != nil {
		this.Log.Error("minerId:%+v,err:%+v", minerId, err.Error())
	}
	OneHundredAndEightyDaysRewardDecimal := todayZeroHourVestingFundsDecimal.Sub(nowVestingFundsDecimal).Add(todayRewardDecimal.Mul(decimal.NewFromFloat(0.75)))
	result.TodayVesting, _ = this.CommonFunc.FilConvertByDecimal(OneHundredAndEightyDaysRewardDecimal).Float64()
	todayImmediateReleaseDecimal := todayRewardDecimal.Mul(decimal.NewFromFloat(0.25))
	result.TodayImmediateRelease, _ = this.CommonFunc.FilConvertByDecimal(todayImmediateReleaseDecimal).Float64()
	ReleaseFilDecimal := OneHundredAndEightyDaysRewardDecimal.Add(todayImmediateReleaseDecimal)
	result.TodayReleaseFil, _ = this.CommonFunc.FilConvertByDecimal(ReleaseFilDecimal).Float64()

	if yesterdayCacheDataOk && result.DoneYesterdaySyncTotal && result.DoneYesterdaySyncMsg && result.DoneYesterdaySyncRewardPenalty {
		result.YesterdayWinPerDay = yesterdayCacheData.YesterdayWinPerDay
		result.YesterdayLucky = yesterdayCacheData.YesterdayLucky
		result.YesterdayRewardCount = yesterdayCacheData.YesterdayRewardCount
		result.YesterdayRewardFil = yesterdayCacheData.YesterdayRewardFil
		result.YesterdayBurnCount = yesterdayCacheData.YesterdayBurnCount
		result.YesterdayBurnFil = yesterdayCacheData.YesterdayBurnFil
		result.YesterdayBurnList = yesterdayCacheData.YesterdayBurnList
		result.YesterdayPowerGrowth = yesterdayCacheData.YesterdayPowerGrowth
		result.YesterdayReductionsBalances = yesterdayCacheData.YesterdayReductionsBalances
		result.YesterdayPledge = yesterdayCacheData.YesterdayPledge
		result.YesterdayGas = yesterdayCacheData.YesterdayGas
		result.YesterdayCommittedPowerFloat = yesterdayCacheData.YesterdayCommittedPowerFloat
		result.YesterdayEveryTibEarnings = yesterdayCacheData.YesterdayEveryTibEarnings
		result.YesterdayCostPerTib = yesterdayCacheData.YesterdayCostPerTib
		result.YesterdayCostPerTibByGas = yesterdayCacheData.YesterdayCostPerTibByGas
		result.YesterdayCostPerTibByPledge = yesterdayCacheData.YesterdayCostPerTibByPledge
		result.YesterdayReleaseFil = yesterdayCacheData.YesterdayReleaseFil
		result.YesterdayImmediateRelease = yesterdayCacheData.YesterdayImmediateRelease
		result.YesterdayVesting = yesterdayCacheData.YesterdayVesting

	} else {
		yesterdayRewardSeard := bson.D{{"To", minerId}, {"From", "f02"}, {"Time", bson.D{{"$gte", yesterdayZeroHour.Unix()}, {"$lt", todayZeroHour.Unix()}}}}
		yesterdayReward := this.RewardBurnAo.Find(yesterdayRewardSeard, options.Find())
		yesterdayRewardDecimal := decimal.NewFromInt(0)
		if len(yesterdayReward) > 0 {
			for _, singleReward := range yesterdayReward {
				singleRewardDecimal, err := decimal.NewFromString(singleReward.Value)
				if err != nil {
					this.Log.Error("minerId:%+v,err:%+v", minerId, err.Error())
				}
				yesterdayRewardDecimal = yesterdayRewardDecimal.Add(singleRewardDecimal)
				result.YesterdayRewardCount++
			}

			result.YesterdayRewardFil, _ = this.CommonFunc.FilConvertByDecimal(yesterdayRewardDecimal).Float64()
		}

		result.YesterdayBurnList = this.RewardBurnAo.Find(bson.D{{"From", minerId}, {"To", "f099"}, {"Time", bson.D{{"$gte", yesterdayZeroHour.Unix()}, {"$lt", todayZeroHour.Unix()}}}}, options.Find())
		if len(result.YesterdayBurnList) > 0 {
			yesterdayBurnDecimal := decimal.NewFromInt(0)
			for _, singleBurn := range result.YesterdayBurnList {
				singleBurnDecimal, err := decimal.NewFromString(singleBurn.Value)
				if err != nil {
					this.Log.Error("minerId:%+v,err:%+v", minerId, err.Error())
				}
				yesterdayBurnDecimal = yesterdayBurnDecimal.Add(singleBurnDecimal)
				result.YesterdayBurnCount++
			}
			result.YesterdayBurnFil, _ = this.CommonFunc.FilConvertByDecimal(yesterdayBurnDecimal).Float64()
		}

		for i, block := range result.YesterdayBurnList {
			block.Fil, _ = this.CommonFunc.FilConvert(block.Value)
			block.TimeString = time.Unix(result.TotalMiner.Time, 0).In(common.LocationTime).Format("2006-01-02 15:04:05")
			result.YesterdayBurnList[i] = block
		}
		if !todayZeroHourPow.MinerPower.QualityAdjPower.IsZero() && !todayZeroHourPow.TotalPower.QualityAdjPower.IsZero() {
			qpercI := types.BigDiv(types.BigMul(todayZeroHourPow.MinerPower.QualityAdjPower, types.NewInt(1000000)), todayZeroHourPow.TotalPower.QualityAdjPower)
			expWinChance := float64(types.BigMul(qpercI, types.NewInt(build.BlocksPerEpoch)).Int64()) / 1000000
			if expWinChance > 0 {
				if expWinChance > 1 {
					expWinChance = 1
				}
				winRate := time.Duration(float64(time.Second*time.Duration(build.BlockDelaySecs)) / expWinChance)
				result.YesterdayWinPerDay = float64(time.Hour*24) / float64(winRate)
				result.YesterdayLucky = float64(result.YesterdayRewardCount) / result.YesterdayWinPerDay * 100
			}
		}

		yesterdayZeroHourBlock := this.TotalAo.FindOne(bson.D{{"MinerAddress", minerId}, {"Time", bson.D{{"$eq", yesterdayZeroHour.Unix()}}}}, opts)
		if yesterdayZeroHourBlock.Height == 0 {
			yesterdayZeroHourBlock = this.TotalAo.FindOne(bson.D{{"MinerAddress", minerId}, {"Time", bson.D{{"$eq", yesterdayZeroHour.Unix() - 30}}}}, opts)
		}
		yesterdayZeroCommittedPowerDecimal, err := decimal.NewFromString(yesterdayZeroHourBlock.CommittedPower)
		if err != nil {
			this.Log.Error("minerId:%+v,err:%+v", minerId, err.Error())
		}
		result.YesterdayPowerGrowth, _ = this.CommonFunc.SizeTibConvertByDecimal(todayZeroCommittedPowerDecimal.Sub(yesterdayZeroCommittedPowerDecimal)).Float64()

		yesterdayBlocksOpt := options.Find().SetSort(bson.D{{"Height", 1}})

		YesterdayPledgeDecimal := decimal.NewFromInt(0)
		YesterdayGasDecimal := decimal.NewFromInt(0)
		yesterdayMag := this.MessageAo.Find(
			bson.D{{"To", minerId},
				{"Time", bson.D{
					{"$gte", yesterdayZeroHour.Unix()},
					{"$lt", todayZeroHour.Unix()}}}},
			yesterdayBlocksOpt)
		for _, singleMsg := range yesterdayMag {
			if singleMsg.Method == 6 ||
				singleMsg.Method == 7 {

				BaseFeeBurnDecimal, err := decimal.NewFromString(singleMsg.BaseFeeBurn)
				if err != nil {
					this.Log.Error("minerId:%+v,err:%+v", minerId, err.Error())
				}

				OverEstimationBurnDecimal, err := decimal.NewFromString(singleMsg.OverEstimationBurn)
				if err != nil {
					this.Log.Error("minerId:%+v,err:%+v", minerId, err.Error())
				}

				MinerTipDecimal, err := decimal.NewFromString(singleMsg.MinerTip)
				if err != nil {
					this.Log.Error("minerId:%+v,err:%+v", minerId, err.Error())
				}

				YesterdayGasDecimal = YesterdayGasDecimal.Add(BaseFeeBurnDecimal).Add(OverEstimationBurnDecimal).Add(MinerTipDecimal)

				ValueDecimal, err := decimal.NewFromString(singleMsg.Value)
				if err != nil {
					this.Log.Error("minerId:%+v,err:%+v", minerId, err.Error())
				}
				YesterdayPledgeDecimal = YesterdayPledgeDecimal.Add(ValueDecimal)
			}
		}
		result.YesterdayGas, _ = this.CommonFunc.FilConvertByDecimal(YesterdayGasDecimal).Float64()

		YesterdayReductionsBalancesDecimal := YesterdayPledgeDecimal.Add(YesterdayGasDecimal)
		result.YesterdayReductionsBalances, _ = this.CommonFunc.FilConvertByDecimal(YesterdayReductionsBalancesDecimal).Float64()
		result.YesterdayPledge, _ = this.CommonFunc.FilConvertByDecimal(YesterdayPledgeDecimal).Float64()
		result.YesterdayCommittedPowerFloat, _ = this.CommonFunc.SizeTibConvertByDecimal(yesterdayZeroCommittedPowerDecimal).Float64()
		if todayZeroQualityAdjPowerFloat != 0 && result.YesterdayRewardFil != 0 {
			result.YesterdayEveryTibEarnings = result.YesterdayRewardFil / todayZeroQualityAdjPowerFloat
		}
		if result.YesterdayPowerGrowth != 0 && result.YesterdayReductionsBalances != 0 {
			result.YesterdayCostPerTib = result.YesterdayReductionsBalances / result.YesterdayPowerGrowth
		}
		if result.YesterdayPowerGrowth != 0 && result.YesterdayGas != 0 {
			result.YesterdayCostPerTibByGas = result.YesterdayGas / result.YesterdayPowerGrowth
		}
		if result.YesterdayPowerGrowth != 0 && result.YesterdayPledge != 0 {
			result.YesterdayCostPerTibByPledge = result.YesterdayPledge / result.YesterdayPowerGrowth
		}

		yesterdayVestingFundsDecimal, err := decimal.NewFromString(yesterdayZeroHourBlock.VestingFunds)
		if err != nil {
			this.Log.Error("minerId:%+v,err:%+v", minerId, err.Error())
		}
		YesterdayOneHundredAndEightyDaysRewardDecimal := yesterdayVestingFundsDecimal.Sub(todayZeroHourVestingFundsDecimal).Add(yesterdayRewardDecimal.Mul(decimal.NewFromFloat(0.75)))
		result.YesterdayVesting, _ = this.CommonFunc.FilConvertByDecimal(YesterdayOneHundredAndEightyDaysRewardDecimal).Float64()
		yesterdayImmediateReleaseDecimal := yesterdayRewardDecimal.Mul(decimal.NewFromFloat(0.25))
		result.YesterdayImmediateRelease, _ = this.CommonFunc.FilConvertByDecimal(yesterdayImmediateReleaseDecimal).Float64()
		yesterdayReleaseFilDecimal := YesterdayOneHundredAndEightyDaysRewardDecimal.Add(yesterdayImmediateReleaseDecimal)
		result.YesterdayReleaseFil, _ = this.CommonFunc.FilConvertByDecimal(yesterdayReleaseFilDecimal).Float64()

	}

	result.YesterdayRoundWinner = this.TotalAo.CountDocuments(bson.D{{"MinerAddress", minerId}, {"RoundWinner", 1}, {"Time", bson.D{{"$gte", yesterdayZeroHour.Unix()}, {"$lt", todayZeroHour.Unix()}}}}, options.Count())

	if result.QualityAdjPowerFloat != 0 && result.TodayRewardFil != 0 {
		result.TodayEveryTibEarnings = result.TodayRewardFil / result.QualityAdjPowerFloat
	}

	if result.TodayPowerGrowth != 0 && result.TodayReductionsBalances != 0 {
		result.TodayCostPerTib = result.TodayReductionsBalances / result.TodayPowerGrowth
	}

	if result.TodayPowerGrowth != 0 && result.TodayGas != 0 {
		result.TodayCostPerTibByGas = result.TodayGas / result.TodayPowerGrowth
	}

	if result.TodayPowerGrowth != 0 && result.TodayPledge != 0 {
		result.TodayCostPerTibByPledge = result.TodayPledge / result.TodayPowerGrowth
	}

	if result.DoneYesterdaySyncTotal && result.DoneYesterdaySyncMsg && result.DoneYesterdaySyncRewardPenalty {
		YesterdayData.Store(YesterdayDataKey, result)
	}

	return result
}

var SyncOldDataContext context.Context
var SyncOldDataContextCancel context.CancelFunc

func (this *DefineController) syncOldData() {
	SyncOldDataContext, SyncOldDataContextCancel = context.WithCancel(context.Background())
	this.AddBatchTotalByHeight(SyncOldDataContext, int64(common.NowTipSet.Height())-2)
	this.RewardBurnAo.AddByFilfoxReward(SyncOldDataContext)
	this.RewardBurnAo.AddByFilfoxMessages(SyncOldDataContext)
	this.RewardBurnAo.SyncByFilfoxBlock(SyncOldDataContext)
}

func (this *DefineController) AgainSyncOldData() {
	SyncOldDataContextCancel()
	this.syncOldData()
}

func (this *DefineController) GetDataByHeight(targetHeight int64) {

	//this.Log.Debug("GetDataByHeight：%+v", targetHeight)

	targetTipSet, err := common.LotusApi.ChainGetTipSetByHeight(context.TODO(), abi.ChainEpoch(targetHeight), common.NowTipSet.Key())
	if err != nil {
		this.Log.Critical("%+v", err)
	}
	this.TotalAo.AddByHeight(targetTipSet)
	this.RewardBurnAo.AddByHeight(targetTipSet, false)

}

func (this *DefineController) AddBatchTotalByHeight(ctx context.Context, targetHeight int64) {
	go func() {
		defer CatchCrash(func(exception Exception) {
			this.Log.Critical("AddBatchTotalByHeight Crash Code:[%d] Message:[%s]\nStackTrace:[%s]", exception.GetCode(), exception.GetMessage(), exception.GetStackTrace())
			if len(SyncTotalMinersByHeight) > 0 {
				time.Sleep(time.Minute)
				this.AddBatchTotalByHeight(ctx, int64(common.NowTipSet.Height())-2)
			}
		})

		this.Log.Debug("AddBatchTotalByHeight:%+v", targetHeight)

		if targetHeight <= 99 {
			return
		}

		SyncTotalMinersByHeight = make(map[string]int64)
		minerIds := this.MinerAo.GetMinerIds()
		minerIdsMap := this.MinerAo.GetMinerIdsOutMap()

		for _, singleMinerId := range minerIds {
			SyncTotalMinersByHeight[singleMinerId] = int64(0)
		}

		for {
			datas := this.TotalAo.FindStruct(total.TotalMiner{Height: targetHeight}, options.Find())
			// 这高度是否有矿工没同步
			ok := false
			for _, a := range datas {
				for b, _ := range SyncTotalMinersByHeight {
					if a.MinerAddress == b {
						ok = true
						break
					}
				}
				if !ok {
					break
				}
			}
			if ok {
				for s, _ := range SyncTotalMinersByHeight {
					SyncTotalMinersByHeight[s] = targetHeight
				}
				targetHeight--
				continue
			}

			targetTipSet, err := common.LotusApi.ChainGetTipSetByHeight(context.TODO(), abi.ChainEpoch(targetHeight), common.NowTipSet.Key())
			if err != nil {
				panic(err)
			}

			if (targetHeight - 1) == int64(targetTipSet.Height()) {
				targetHeight--
				continue
			}

			minerIds := this.MinerAo.GetMinerIds()
			for _, singleMinerId := range minerIds {
				this.TotalAo.AddTotal(targetTipSet, singleMinerId)
				SyncTotalMinersByHeight[singleMinerId] = targetHeight
				if int64(targetTipSet.Blocks()[0].Timestamp) < minerIdsMap[singleMinerId].CreateTimestamp {
					delete(SyncTotalMinersByHeight, singleMinerId)
				}
			}
			if len(SyncTotalMinersByHeight) == 0 {
				break
			}
			targetHeight--
			select {
			case <-ctx.Done():
				return
			default:
			}
		}

	}()

}

type TotalSituationList struct {
	MinerGeneralize
	miner.MinerBase
	TodayAbnormalBlock     int
	YesterdayAbnormalBlock int
}

type TotalSituation struct {
	TotalBalance    float64
	QualityAdjPower float64
	PowerRatio      float64 // 算力全网占比
	RewardCount     int
	RewardFil       float64
	Height          int64
	List            []TotalSituationList
}

func (this *DefineController) GetTotal() TotalSituation {

	result := TotalSituation{}
	client := this.ClientAo.IsLogin()
	minerIds := []string{}

	for _, singleAuthority := range client.Authority {
		if _, ok := this.MinerAo.GetMinerAddress()[singleAuthority]; ok {
			minerIds = append(minerIds, singleAuthority)
		}
	}

	if len(minerIds) == 0 {
		return TotalSituation{}
	}

	totalMap := map[string]total.TotalMiner{}
	opts := options.FindOne().SetSort(bson.D{{"Height", -1}})
	isEqualHeight := true //是否相同一个高度
	height := int64(0)
	totalBalances := decimal.NewFromInt(0)
	qualityAdjPowers := decimal.NewFromInt(0)
	minerReward := map[string]decimal.Decimal{}
	minerRewardNums := map[string]int{}
	searchMiner := bson.A{}
	for _, singleMinerId := range minerIds {
		minerReward[singleMinerId] = decimal.Decimal{}
		minerRewardNums[singleMinerId] = 0
		searchTotal := total.TotalMiner{MinerAddress: singleMinerId}
		totalMiner := this.TotalAo.FindOneStruct(searchTotal, opts)
		if height == 0 {
			height = totalMiner.Height
		} else {
			if isEqualHeight && height != totalMiner.Height {
				isEqualHeight = false
			}
		}
		if height < totalMiner.Height {
			height = totalMiner.Height
		}
		totalMap[singleMinerId] = totalMiner

		totalBalance, err := decimal.NewFromString(totalMiner.TotalBalance)
		if err != nil {
			this.Log.Error("minerId:%+v,err:%+v", singleMinerId, err.Error())
		}
		totalBalances = totalBalances.Add(totalBalance)

		qualityAdjPower, err := decimal.NewFromString(totalMiner.QualityAdjPower)
		if err != nil {
			this.Log.Error("minerId:%+v,err:%+v", singleMinerId, err.Error())
		}
		qualityAdjPowers = qualityAdjPowers.Add(qualityAdjPower)
		searchMiner = append(searchMiner, bson.D{{"To", singleMinerId}})
	}

	result.Height = height
	result.TotalBalance, _ = this.CommonFunc.FilConvertByDecimal(totalBalances).Float64()
	result.QualityAdjPower, _ = this.CommonFunc.SizeTibConvertByDecimal(qualityAdjPowers).Float64()
	targetTipSet, err := common.LotusApi.ChainGetTipSetByHeight(context.TODO(), abi.ChainEpoch(height), common.NowTipSet.Key())
	if err != nil {
		panic(err)
	}

	if len(minerIds) > 0 {
		pow, err := common.LotusApi.StateMinerPower(context.TODO(), address.Address{}, targetTipSet.Key())
		if err == nil {
			if !qualityAdjPowers.IsZero() {
				result.PowerRatio, _ = qualityAdjPowers.Mul(decimal.NewFromInt(1000000)).Div(decimal.NewFromBigInt(pow.TotalPower.QualityAdjPower.Int, 0)).Div(decimal.NewFromInt(10000)).Float64()
			}
		} else {
			this.Log.Debug("%+v", err)
		}
	}

	allRewardSearch := bson.D{{"From", "f02"}, {"$or", searchMiner}}
	allReward := this.RewardBurnAo.Find(allRewardSearch, options.Find())

	totalReward := decimal.Decimal{}
	totalRewardNums := 0
	for _, singleReward := range allReward {
		singleRewardDecimal, err := decimal.NewFromString(singleReward.Value)
		if err != nil {
			this.Log.Error("minerId:%+v,err:%+v", singleReward.To, err.Error())
		}
		minerReward[singleReward.To] = minerReward[singleReward.To].Add(singleRewardDecimal)
		minerRewardNums[singleReward.To]++
	}

	for _, singleReward := range minerReward {
		totalReward = totalReward.Add(singleReward)
	}

	for _, singleReward := range minerRewardNums {
		totalRewardNums += singleReward
	}

	result.RewardFil, _ = this.CommonFunc.FilConvertByDecimal(totalReward).Float64()
	result.RewardCount = totalRewardNums

	for _, singleMinerId := range minerIds {
		singleTotalSituationList := TotalSituationList{}
		singleMiner := this.MinerAo.FindOne(miner.MinerBase{MinerId: singleMinerId}, options.FindOne())
		singleTotalSituationList.MinerGeneralize = this.GetMinerTotalByMinerId(singleMinerId)
		singleTotalSituationList.MinerId = singleMiner.MinerId
		singleTotalSituationList.PoolName = singleMiner.PoolName
		singleTotalSituationList.Size = singleMiner.Size
		singleTotalSituationList.Balance, _ = this.CommonFunc.FilConvert(totalMap[singleMinerId].TotalBalance)
		singleTotalSituationList.Power, _ = this.CommonFunc.SizeTibConvert(totalMap[singleMinerId].QualityAdjPower)
		singleTotalSituationList.RewardFil, _ = this.CommonFunc.FilConvertByDecimal(minerReward[singleMiner.MinerId]).Float64()
		singleTotalSituationList.RewardCount = minerRewardNums[singleMiner.MinerId]
		singleTotalSituationList.TodayAbnormalBlock = int(singleTotalSituationList.TodayRoundWinner) - singleTotalSituationList.TodayRewardCount
		singleTotalSituationList.YesterdayAbnormalBlock = int(singleTotalSituationList.YesterdayRoundWinner) - singleTotalSituationList.YesterdayRewardCount
		result.List = append(result.List, singleTotalSituationList)
	}

	return result
}

func (this *DefineController) SyncExpend() {
	IsSyncExpend = true
	nowTime := time.Now().In(common.LocationTime)
	yesterday := nowTime.AddDate(0, 0, -1)
	yesterZeroHour := time.Date(yesterday.Year(), yesterday.Month(), yesterday.Day(), 0, 0, 0, 0, common.LocationTime)

	minerMap := this.MinerAo.GetMinerIdsOutMap()
	for {
		for singleMinerId, singleMiner := range minerMap {
			if singleMiner.CreateTimestamp == 0 {
				singleMiner.CreateTimestamp = this.MinerAo.GetCreateTimestamp(singleMinerId)
				minerMap[singleMinerId] = singleMiner
			}
			if yesterZeroHour.Unix() < singleMiner.CreateTimestamp {
				continue
			}
			result := this.expend(singleMinerId, yesterZeroHour)
			this.ExpendAo.Upsert(result)
		}
		if len(minerMap) == 0 {
			break
		}
		yesterZeroHour = yesterZeroHour.AddDate(0, 0, -1)
		if yesterZeroHour.Unix() < 1598256000 {
			break
		}
	}
	IsSyncExpend = false

}

func (this *DefineController) SyncIncome() {
	IsSyncIncome = true
	nowTime := time.Now().In(common.LocationTime)
	yesterday := nowTime.AddDate(0, 0, -1)
	yesterZeroHour := time.Date(yesterday.Year(), yesterday.Month(), yesterday.Day(), 0, 0, 0, 0, common.LocationTime)

	minerMap := this.MinerAo.GetMinerIdsOutMap()
	for {
		for singleMinerId, singleMiner := range minerMap {
			if singleMiner.CreateTimestamp == 0 {
				singleMiner.CreateTimestamp = this.MinerAo.GetCreateTimestamp(singleMinerId)
				minerMap[singleMinerId] = singleMiner
			}
			if yesterZeroHour.Unix() < singleMiner.CreateTimestamp {
				continue
			}
			result := this.income(singleMinerId, yesterZeroHour)
			this.IncomeAo.Upsert(result)
		}
		if len(minerMap) == 0 {
			break
		}
		yesterZeroHour = yesterZeroHour.AddDate(0, 0, -1)
		if yesterZeroHour.Unix() < 1598256000 {
			break
		}
	}
	IsSyncIncome = false
}

func (this *DefineController) expend(minerId string, dataTime time.Time) expend.Expend {
	singleMinerAddr := this.MinerAo.GetMinerAddress()[minerId]
	result := expend.Expend{}
	dataTime = time.Date(dataTime.Year(), dataTime.Month(), dataTime.Day(), 0, 0, 0, 0, common.LocationTime)
	tomorrow := dataTime.AddDate(0, 0, 1)
	result.MinerId = minerId
	result.Time = dataTime
	PledgeDecimal := decimal.NewFromInt(0)
	GasDecimal := decimal.NewFromInt(0)
	BlocksOpt := options.Find()
	Mags := this.MessageAo.Find(
		bson.D{{"To", minerId},
			{"Time", bson.D{
				{"$gte", dataTime.Unix()},
				{"$lt", tomorrow.Unix()}}}},
		BlocksOpt)
	for _, singleMsg := range Mags {
		if singleMsg.Method == 6 ||
			singleMsg.Method == 7 {

			BaseFeeBurnDecimal, err := decimal.NewFromString(singleMsg.BaseFeeBurn)
			if err != nil {
				this.Log.Error("minerId:%+v,err:%+v", minerId, err.Error())
			}

			OverEstimationBurnDecimal, err := decimal.NewFromString(singleMsg.OverEstimationBurn)
			if err != nil {
				this.Log.Error("minerId:%+v,err:%+v", minerId, err.Error())
			}

			MinerTipDecimal, err := decimal.NewFromString(singleMsg.MinerTip)
			if err != nil {
				this.Log.Error("minerId:%+v,err:%+v", minerId, err.Error())
			}

			GasDecimal = GasDecimal.Add(BaseFeeBurnDecimal).Add(OverEstimationBurnDecimal).Add(MinerTipDecimal)

			ValueDecimal, err := decimal.NewFromString(singleMsg.Value)
			if err != nil {
				this.Log.Error("minerId:%+v,err:%+v", minerId, err.Error())
			}
			PledgeDecimal = PledgeDecimal.Add(ValueDecimal)
		}
	}
	result.Pledge, _ = this.CommonFunc.FilConvertByDecimal(PledgeDecimal).Float64()
	result.Gas, _ = this.CommonFunc.FilConvertByDecimal(GasDecimal).Float64()

	result.PledgeString = this.CommonFunc.FilConvertByDecimal(PledgeDecimal).String()
	result.GasString = this.CommonFunc.FilConvertByDecimal(GasDecimal).String()

	ConsumeBalancesDecimal := PledgeDecimal.Add(GasDecimal)
	result.ConsumeBalances, _ = this.CommonFunc.FilConvertByDecimal(ConsumeBalancesDecimal).Float64()
	result.ConsumeBalancesString = this.CommonFunc.FilConvertByDecimal(ConsumeBalancesDecimal).String()

	tomorrowZeroHourBlock := this.TotalAo.FindOne(bson.D{{"MinerAddress", minerId}, {"Time", bson.D{{"$eq", tomorrow.Unix()}}}}, options.FindOne())
	if tomorrowZeroHourBlock.Height == 0 {
		epochTimeParse := tomorrow.Format("2006-01-02 15:04:05")
		targetHeight, err := this.CommonFunc.TimeToEpoch(epochTimeParse)
		if err != nil {
			panic(err)
		}
		targetTipSet, err := common.LotusApi.ChainGetTipSetByHeight(context.TODO(), abi.ChainEpoch(targetHeight), common.NowTipSet.Key())
		if err != nil {
			panic(err)
		}

		secCounts, err := common.LotusApi.StateMinerSectorCount(context.TODO(), singleMinerAddr, targetTipSet.Key())
		if err == nil {
			mi, err := common.LotusApi.StateMinerInfo(context.TODO(), singleMinerAddr, targetTipSet.Key())
			if err == nil {
				tomorrowZeroHourBlock.CommittedPower = types.BigMul(types.NewInt(secCounts.Live), types.NewInt(uint64(mi.SectorSize))).String()
			}
		}
	}
	if tomorrowZeroHourBlock.CommittedPower == "" {
		tomorrowZeroHourBlock.CommittedPower = "0"
	}
	tomorrowZeroCommittedPowerDecimal, err := decimal.NewFromString(tomorrowZeroHourBlock.CommittedPower)
	if err != nil {
		this.Log.Error("minerId:%+v,value:%+v,err:%+v", minerId, tomorrowZeroHourBlock.CommittedPower, err.Error())
	}
	todayZeroHourBlock := this.TotalAo.FindOne(bson.D{{"MinerAddress", minerId}, {"Time", bson.D{{"$eq", dataTime.Unix()}}}}, options.FindOne())
	if todayZeroHourBlock.Height == 0 {
		epochTimeParse := dataTime.Format("2006-01-02 15:04:05")
		targetHeight, err := this.CommonFunc.TimeToEpoch(epochTimeParse)
		if err != nil {
			panic(err)
		}
		targetTipSet, err := common.LotusApi.ChainGetTipSetByHeight(context.TODO(), abi.ChainEpoch(targetHeight), common.NowTipSet.Key())
		if err != nil {
			panic(err)
		}

		secCounts, err := common.LotusApi.StateMinerSectorCount(context.TODO(), singleMinerAddr, targetTipSet.Key())
		if err == nil {
			mi, err := common.LotusApi.StateMinerInfo(context.TODO(), singleMinerAddr, targetTipSet.Key())
			if err == nil {
				todayZeroHourBlock.CommittedPower = types.BigMul(types.NewInt(secCounts.Live), types.NewInt(uint64(mi.SectorSize))).String()
			}
		}
	}

	if todayZeroHourBlock.CommittedPower == "" {
		todayZeroHourBlock.CommittedPower = "0"
	}
	todayZeroCommittedPowerDecimal, err := decimal.NewFromString(todayZeroHourBlock.CommittedPower)
	if err != nil {
		this.Log.Error("minerId:%+v,value:%+v,err:%+v", minerId, todayZeroHourBlock.CommittedPower, err.Error())
	}
	PowerGrowthDecimal := tomorrowZeroCommittedPowerDecimal.Sub(todayZeroCommittedPowerDecimal)
	result.PowerGrowth, _ = this.CommonFunc.SizeTibConvertByDecimal(PowerGrowthDecimal).Float64()
	result.PowerGrowthString = this.CommonFunc.SizeTibConvertByDecimal(PowerGrowthDecimal).String()

	if result.PowerGrowth != 0 && result.ConsumeBalances != 0 {
		result.CostPerTib = result.ConsumeBalances / result.PowerGrowth
	}
	if result.PowerGrowth != 0 && result.Gas != 0 {
		result.CostPerTibByPledge = result.Gas / result.PowerGrowth
	}
	if result.PowerGrowth != 0 && result.Pledge != 0 {
		result.CostPerTibByGas = result.Pledge / result.PowerGrowth
	}

	burnList := this.RewardBurnAo.Find(bson.D{{"From", minerId}, {"To", "f099"},
		{"Time", bson.D{
			{"$gte", dataTime.Unix()},
			{"$lt", tomorrow.Unix()}}}},
		options.Find())
	if len(burnList) > 0 {
		yesterdayBurnDecimal := decimal.NewFromInt(0)
		for _, singleBurn := range burnList {
			singleBurnDecimal, err := decimal.NewFromString(singleBurn.Value)
			if err != nil {
				this.Log.Error("minerId:%+v,err:%+v", minerId, err.Error())
			}
			yesterdayBurnDecimal = yesterdayBurnDecimal.Add(singleBurnDecimal)
		}
		result.Penalty, _ = this.CommonFunc.FilConvertByDecimal(yesterdayBurnDecimal).Float64()
	}

	return result
}

func (this *DefineController) SyncNowData() {
	common.GetNowTipSet()
	// -2为了解决实时块有些信息没有计算好或者最新高度块没出完
	this.GetDataByHeight(int64(common.NowTipSet.Height()) - 2)
}

func (this *DefineController) SyncYesterday() {
	go func() {
		defer CatchCrash(func(exception Exception) {
			this.Log.Critical("SyncYesterdayTotal Crash Code:[%d] Message:[%s]\nStackTrace:[%s]", exception.GetCode(), exception.GetMessage(), exception.GetStackTrace())
		})
		var nowtipSet types.TipSet
		nowtipSet = *common.NowTipSet
		minerIds := this.MinerAo.GetMinerIds()
		for i := 0; i < 2888; i++ {
			height := int64(nowtipSet.Height()) - int64(i)
			datas := this.TotalAo.FindStruct(total.TotalMiner{Height: height}, options.Find())
			if len(datas) == len(minerIds) {
				continue
			}
			this.Log.Debug("%+v", height)
			targetTipSet, err := common.LotusApi.ChainGetTipSetByHeight(context.TODO(), abi.ChainEpoch(height), common.NowTipSet.Key())
			if err != nil {
				panic(err)
			}

			this.TotalAo.AddByHeight(targetTipSet)
		}
	}()

	go func() {
		defer CatchCrash(func(exception Exception) {
			this.Log.Critical("SyncYesterdayIncomeAndExpend Crash Code:[%d] Message:[%s]\nStackTrace:[%s]", exception.GetCode(), exception.GetMessage(), exception.GetStackTrace())
		})
		minerIds := this.MinerAo.GetMinerIds()
		nowTime := time.Now().In(common.LocationTime)
		yesterday := nowTime.AddDate(0, 0, -1)
		yesterdayZeroHour := time.Date(yesterday.Year(), yesterday.Month(), yesterday.Day(), 0, 0, 0, 0, common.LocationTime)

		for _, singleMinerid := range minerIds {
			result := this.expend(singleMinerid, yesterdayZeroHour)
			this.ExpendAo.Upsert(result)
			result2 := this.income(singleMinerid, yesterdayZeroHour)
			this.IncomeAo.Upsert(result2)
		}
	}()

	go func() {
		defer CatchCrash(func(exception Exception) {
			this.Log.Critical("SyncYesterdayByFilfox Crash Code:[%d] Message:[%s]\nStackTrace:[%s]", exception.GetCode(), exception.GetMessage(), exception.GetStackTrace())
		})
		this.RewardBurnAo.SyncYesterdayByFilfox()
	}()
	go func() {
		defer CatchCrash(func(exception Exception) {
			this.Log.Critical("SyncYesterdayMessagesByFilfox Crash Code:[%d] Message:[%s]\nStackTrace:[%s]", exception.GetCode(), exception.GetMessage(), exception.GetStackTrace())
		})
		this.RewardBurnAo.SyncYesterdayMessagesByFilfox()
	}()
}

func (this *DefineController) income(minerId string, dataTime time.Time) income.Income {
	result := income.Income{}
	singleMinerAddr := this.MinerAo.GetMinerAddress()[minerId]
	dataTime = time.Date(dataTime.Year(), dataTime.Month(), dataTime.Day(), 0, 0, 0, 0, common.LocationTime)
	tomorrow := dataTime.AddDate(0, 0, 1)
	result.MinerId = minerId
	result.Time = dataTime

	result.RoundWinner = int8(this.TotalAo.CountDocuments(bson.D{{"MinerAddress", minerId}, {"RoundWinner", 1}, {"Time", bson.D{{"$gte", dataTime.Unix()}, {"$lt", tomorrow.Unix()}}}}, options.Count()))
	if result.RoundWinner == 0 {
		data := this.TotalAo.FindOne(bson.D{{"MinerAddress", minerId}, {"RoundWinner", 1}, {"Time", bson.D{{"$gte", dataTime.Unix()}, {"$lt", tomorrow.Unix()}}}}, options.FindOne())
		if data.RoundWinner != total.TotalRoundWinnerEnum.YES &&
			data.RoundWinner != total.TotalRoundWinnerEnum.NO {
			result.RoundWinner = -1
		}
	}

	RewardSeard := bson.D{{"To", minerId}, {"From", "f02"}, {"Time", bson.D{{"$gte", dataTime.Unix()}, {"$lt", tomorrow.Unix()}}}}
	Reward := this.RewardBurnAo.Find(RewardSeard, options.Find())
	RewardDecimal := decimal.NewFromInt(0)
	if len(Reward) > 0 {
		for _, singleReward := range Reward {
			singleRewardDecimal, err := decimal.NewFromString(singleReward.Value)
			if err != nil {
				this.Log.Error("minerId:%+v,err:%+v", minerId, err.Error())
			}
			RewardDecimal = RewardDecimal.Add(singleRewardDecimal)
			result.RewardCount++
		}

		result.RewardFil, _ = this.CommonFunc.FilConvertByDecimal(RewardDecimal).Float64()
	}

	dataTimeHeight, err := this.CommonFunc.TimeToEpoch(dataTime.In(common.LocationTime).Format("2006-01-02 15:04:05"))
	if err == nil {
		targetTipSet, err := common.LotusApi.ChainGetTipSetByHeight(context.TODO(), abi.ChainEpoch(dataTimeHeight), common.NowTipSet.Key())
		if err == nil {
			todayZeroHourPow, err := common.LotusApi.StateMinerPower(context.TODO(), singleMinerAddr, targetTipSet.Key())
			if err == nil {
				if !todayZeroHourPow.MinerPower.QualityAdjPower.IsZero() && !todayZeroHourPow.TotalPower.QualityAdjPower.IsZero() {
					qpercI := types.BigDiv(types.BigMul(todayZeroHourPow.MinerPower.QualityAdjPower, types.NewInt(1000000)), todayZeroHourPow.TotalPower.QualityAdjPower)
					expWinChance := float64(types.BigMul(qpercI, types.NewInt(build.BlocksPerEpoch)).Int64()) / 1000000
					if expWinChance > 0 {
						if expWinChance > 1 {
							expWinChance = 1
						}
						winRate := time.Duration(float64(time.Second*time.Duration(build.BlockDelaySecs)) / expWinChance)
						result.WinPerDay = float64(time.Hour*24) / float64(winRate)
						result.Lucky = float64(result.RewardCount) / result.WinPerDay * 100
					}
				}
				if !todayZeroHourPow.MinerPower.QualityAdjPower.IsZero() && !RewardDecimal.IsZero() {
					powD, err := decimal.NewFromString(todayZeroHourPow.MinerPower.QualityAdjPower.String())
					if err == nil {
						result.EveryTibEarnings, _ = RewardDecimal.Div(powD).Float64()
					}
				}
			}
		}
	}

	dataTimeZeroHourBlock := this.TotalAo.FindOne(bson.D{{"MinerAddress", minerId}, {"Time", bson.D{{"$eq", dataTime.Unix()}}}}, options.FindOne())
	if dataTimeZeroHourBlock.Height == 0 {
		dataTimeZeroHourBlock = this.TotalAo.FindOne(bson.D{{"MinerAddress", minerId}, {"Time", bson.D{{"$eq", dataTime.Unix() - 30}}}}, options.FindOne())
	}

	if dataTimeZeroHourBlock.VestingFunds == "" || dataTimeZeroHourBlock.VestingFunds == "0" {
		this.TotalAo.SyncVestingFunds(minerId, dataTimeHeight)
		dataTimeZeroHourBlock = this.TotalAo.FindOne(bson.D{{"MinerAddress", minerId}, {"Time", bson.D{{"$eq", dataTime.Unix()}}}}, options.FindOne())
		if dataTimeZeroHourBlock.Height == 0 {
			dataTimeZeroHourBlock = this.TotalAo.FindOne(bson.D{{"MinerAddress", minerId}, {"Time", bson.D{{"$eq", dataTime.Unix() - 30}}}}, options.FindOne())
		}
	}

	tomorrowZeroHourBlock := this.TotalAo.FindOne(bson.D{{"MinerAddress", minerId}, {"Time", bson.D{{"$eq", tomorrow.Unix()}}}}, options.FindOne())
	if tomorrowZeroHourBlock.Height == 0 {
		tomorrowZeroHourBlock = this.TotalAo.FindOne(bson.D{{"MinerAddress", minerId}, {"Time", bson.D{{"$eq", tomorrow.Unix() - 30}}}}, options.FindOne())
	}
	tomorrowHeight, err := this.CommonFunc.TimeToEpoch(tomorrow.In(common.LocationTime).Format("2006-01-02 15:04:05"))
	if err == nil {
		if tomorrowZeroHourBlock.VestingFunds == "" || tomorrowZeroHourBlock.VestingFunds == "0" {
			this.TotalAo.SyncVestingFunds(minerId, tomorrowHeight)
			tomorrowZeroHourBlock = this.TotalAo.FindOne(bson.D{{"MinerAddress", minerId}, {"Time", bson.D{{"$eq", tomorrow.Unix()}}}}, options.FindOne())
			if tomorrowZeroHourBlock.Height == 0 {
				tomorrowZeroHourBlock = this.TotalAo.FindOne(bson.D{{"MinerAddress", minerId}, {"Time", bson.D{{"$eq", tomorrow.Unix() - 30}}}}, options.FindOne())
			}
		}
	}

	dataVestingFundsDecimal, err := decimal.NewFromString(dataTimeZeroHourBlock.VestingFunds)
	if err != nil {
		this.Log.Error("minerId:%+v,err:%+v", minerId, err.Error())
	}
	tomorrowVestingFundsDecimal, err := decimal.NewFromString(tomorrowZeroHourBlock.VestingFunds)
	if err != nil {
		this.Log.Error("minerId:%+v,err:%+v", minerId, err.Error())
	}
	YesterdayOneHundredAndEightyDaysRewardDecimal := dataVestingFundsDecimal.Sub(tomorrowVestingFundsDecimal).Add(RewardDecimal.Mul(decimal.NewFromFloat(0.75)))
	result.Vesting, _ = this.CommonFunc.FilConvertByDecimal(YesterdayOneHundredAndEightyDaysRewardDecimal).Float64()
	yesterdayImmediateReleaseDecimal := RewardDecimal.Mul(decimal.NewFromFloat(0.25))
	result.ImmediateRelease, _ = this.CommonFunc.FilConvertByDecimal(yesterdayImmediateReleaseDecimal).Float64()
	yesterdayReleaseFilDecimal := YesterdayOneHundredAndEightyDaysRewardDecimal.Add(yesterdayImmediateReleaseDecimal)
	result.ReleaseFil, _ = this.CommonFunc.FilConvertByDecimal(yesterdayReleaseFilDecimal).Float64()

	return result
}

func (this *DefineController) SyncYesterdayMessagesByFilfox() {
	go func() {
		defer CatchCrash(func(exception Exception) {
			this.Log.Critical("SyncYesterdayMessagesByFilfox Crash Code:[%d] Message:[%s]\nStackTrace:[%s]", exception.GetCode(), exception.GetMessage(), exception.GetStackTrace())
		})
		this.Log.Debug("SyncYesterdayMessagesByFilfox:%+v", "AddBatchTotalByRightHeight")
		this.RewardBurnAo.SyncYesterdayMessagesByFilfox()
	}()
}

func (this *DefineController) Test() {
	a, err := common.LotusApi.MsigGetVestingSchedule(context.TODO(), this.MinerAo.GetMinerAddress()["f07830"], common.NowTipSet.Key())
	this.Log.Debug("%+v", a)
	this.Log.Debug("%+v", err)
}

func init() {
	InitDaemon(func(this *DefineController) {
		this.Timer.Cron("*/15 * * * * *", (*DefineController).SyncNowData)
		this.Timer.Cron("1 0 0 * * *", (*DefineController).SyncYesterday)
		//this.SyncYesterday()
		//this.SyncYesterdayMessagesByFilfox()
		this.syncOldData()
		//this.Test()
	})
}
